#include "Drv_W25Q128.h"


#define W25Q128_DEBUG 1
#ifdef W25Q128_DEBUG
#include "stdio.h"
#endif

#define Hard_SPI    hspi1
#define SPI_CS_Port GPIOA
#define SPI_CS_Pin  GPIO_PIN_1

#define W25Q128_DUMMY_BYTE    0xA5
#define W25Q128_CS_Set(X)     HAL_GPIO_WritePin(SPI_CS_Port, SPI_CS_Pin, (X) ?GPIO_PIN_SET :GPIO_PIN_RESET )
#define	W25Q128_Delay(delay)  HAL_Delay(delay)


extern SPI_HandleTypeDef hspi1;
w25q128_t w25q128;

inline uint8_t	W25Q128_SPI(uint8_t	Data)
{
	uint8_t	ret;
	HAL_SPI_TransmitReceive(&Hard_SPI,&Data,&ret,1,100);
	return ret;
}

uint32_t W25Q128_ReadID(void)
{
  uint32_t Temp = 0, Temp0 = 0, Temp1 = 0, Temp2 = 0;
  W25Q128_CS_Set(0);
  W25Q128_SPI(0x9F);
  Temp0 = W25Q128_SPI(W25Q128_DUMMY_BYTE);
  Temp1 = W25Q128_SPI(W25Q128_DUMMY_BYTE);
  Temp2 = W25Q128_SPI(W25Q128_DUMMY_BYTE);
  W25Q128_CS_Set(1);
  Temp = (Temp0 << 16) | (Temp1 << 8) | Temp2;
  return Temp;
}

void W25Q128_ReadUniqID(void)
{
  W25Q128_CS_Set(0);
  W25Q128_SPI(0x4B);
    for(uint8_t	i=0;i<4;i++)
	  W25Q128_SPI(W25Q128_DUMMY_BYTE);
	for(uint8_t	i=0;i<8;i++)
	  w25q128.UniqID[i] = W25Q128_SPI(W25Q128_DUMMY_BYTE);
  W25Q128_CS_Set(1);
}

void W25Q128_WriteEnable(void)
{
  W25Q128_CS_Set(0);
  W25Q128_SPI(0x06);
  W25Q128_CS_Set(1);
  W25Q128_Delay(1);
}

void W25Q128_WriteDisable(void)
{
  W25Q128_CS_Set(0);
  W25Q128_SPI(0x04);
  W25Q128_CS_Set(1);
  W25Q128_Delay(1);
}

uint8_t W25Q128_ReadStatusRegister(uint8_t	SelectStatusRegister_1_2_3)
{
  uint8_t	status=0;
  W25Q128_CS_Set(0);
  if(SelectStatusRegister_1_2_3==1)
  {
  	W25Q128_SPI(0x05);
  	status=W25Q128_SPI(W25Q128_DUMMY_BYTE);
  	w25q128.StatusRegister1 = status;
  }
  else if(SelectStatusRegister_1_2_3==2)
  {
  	W25Q128_SPI(0x35);
  	status=W25Q128_SPI(W25Q128_DUMMY_BYTE);
  	w25q128.StatusRegister2 = status;
  }
  else
  {
  	W25Q128_SPI(0x15);
  	status=W25Q128_SPI(W25Q128_DUMMY_BYTE);
  	w25q128.StatusRegister3 = status;
  }
  W25Q128_CS_Set(1);
  return status;
}

void W25Q128_WriteStatusRegister(uint8_t	SelectStatusRegister_1_2_3,uint8_t Data)
{
  W25Q128_CS_Set(0);
  if(SelectStatusRegister_1_2_3==1)
  {
  	W25Q128_SPI(0x01);
  	w25q128.StatusRegister1 = Data;
  }
  else if(SelectStatusRegister_1_2_3==2)
  {
  	W25Q128_SPI(0x31);
  	w25q128.StatusRegister2 = Data;
  }
  else
  {
  	W25Q128_SPI(0x11);
  	w25q128.StatusRegister3 = Data;
  }
  W25Q128_SPI(Data);
  W25Q128_CS_Set(1);
}

void W25Q128_WaitForWriteEnd(void)
{
  W25Q128_Delay(1);
  W25Q128_CS_Set(0);
  W25Q128_SPI(0x05);
  do
  {
    w25q128.StatusRegister1 = W25Q128_SPI(W25Q128_DUMMY_BYTE);
    W25Q128_Delay(1);
  }
  while ((w25q128.StatusRegister1 & 0x01) == 0x01);
  W25Q128_CS_Set(1);
}

uint32_t W25Q128_Init(void)
{
  w25q128.Lock=1;
  while(HAL_GetTick()<100)
  W25Q128_Delay(1);
  W25Q128_CS_Set(1);
  W25Q128_Delay(100);

  uint32_t	id;

  #if (W25Q128_DEBUG==1)
    printf("w25q128 Init Begin...\r\n");
  #endif
  id=W25Q128_ReadID();

  #if (W25Q128_DEBUG==1)
    printf("w25q128 ID:0x%lX\r\n",id);
  #endif
  switch(id&0x0000FFFF)
  {
  	case 0x401A:	// 	w25q512
  	  #if (W25Q128_DEBUG==1)
  	    printf("Chip: w25q512\r\n");
  	  #endif
      w25q128.Lock=0;
      return 0;
  	break;
  	case 0x4019:	// 	w25q256
  	  #if (W25Q128_DEBUG==1)
  	    printf("Chip: w25q256\r\n");
  	  #endif
      w25q128.Lock=0;
      return 0;
  	break;
  	case 0x4018:	// 	w25q128
  	  w25q128.BlockCount=256;
  	  #if (W25Q128_DEBUG==1)
  	    printf("Chip: w25q128\r\n");
  	  #endif
  	break;
  	case 0x4017:	//	w25q64
  	  #if (W25Q128_DEBUG==1)
  	    printf("Chip: w25q64\r\n");
  	  #endif
      w25q128.Lock=0;		
      return 0;
  	break;
  	case 0x4016:	//	w25q32
  	  #if (W25Q128_DEBUG==1)
  	    printf("Chip: w25q32\r\n");
  	  #endif
      w25q128.Lock=0;
      return 0;
  	break;
  	case 0x4015:	//	w25q16
  	  #if (W25Q128_DEBUG==1)
  	    printf("Chip: w25q16\r\n");
  	  #endif
      w25q128.Lock=0;
      return 0;
  	break;
  	case 0x4014:	//	w25q80
      #if (W25Q128_DEBUG==1)
        printf("Chip: w25q80\r\n");
      #endif
      w25q128.Lock=0;
	  return 0;
  	break;
  	case 0x4013:	//	w25q40
  	  #if (W25Q128_DEBUG==1)
  	    printf("Chip: w25q40\r\n");
  	  #endif
	  w25q128.Lock=0;
      return 0;
  	break;
  	case 0x4012:	//	w25q20
  	  #if (W25Q128_DEBUG==1)
  	    printf("Chip: w25q20\r\n");
  	  #endif
	  w25q128.Lock=0;	
      return 0;
  	break;
  	case 0x4011:	//	w25q10
  	  #if (W25Q128_DEBUG==1)
  	    printf("Chip: w25q10\r\n");
  	  #endif
      w25q128.Lock=0;
      return 0;
  	break;
  	default:
  	  #if (W25Q128_DEBUG==1)
  	    printf("Unknown ID\r\n");
  	  #endif
  	  w25q128.Lock=0;
  	  return 0;
  }
  w25q128.PageSize=256;
  w25q128.SectorSize=0x1000;
  w25q128.SectorCount=w25q128.BlockCount*16;
  w25q128.PageCount=(w25q128.SectorCount*w25q128.SectorSize)/w25q128.PageSize;
  w25q128.BlockSize=w25q128.SectorSize*16;
  w25q128.CapacityInKiloByte=(w25q128.SectorCount*w25q128.SectorSize)/1024;
  W25Q128_ReadUniqID();
  W25Q128_ReadStatusRegister(1);
  W25Q128_ReadStatusRegister(2);
  W25Q128_ReadStatusRegister(3);
  #if (W25Q128_DEBUG==1)
  printf("w25q128 Page Size: %ld Bytes\r\n",(uint32_t)w25q128.PageSize);
  printf("w25q128 Page Count: %ld\r\n",w25q128.PageCount);
  printf("w25q128 Sector Size: %ld Bytes\r\n",w25q128.SectorSize);
  printf("w25q128 Sector Count: %ld\r\n",w25q128.SectorCount);
  printf("w25q128 Block Size: %ld Bytes\r\n",w25q128.BlockSize);
  printf("w25q128 Block Count: %ld\r\n",w25q128.BlockCount);
  printf("w25q128 Capacity: %ld KiloBytes\r\n",w25q128.CapacityInKiloByte);
  printf("w25q128 Init Done\r\n");
  #endif
  w25q128.Lock=0;
  return 1;
}

void W25Q128_EraseChip(void)
{
  while(w25q128.Lock==1)
    W25Q128_Delay(1);
  w25q128.Lock=1;
  #if (W25Q128_DEBUG==1)
    uint32_t	StartTime=HAL_GetTick();
    printf("w25q128 EraseChip Begin...\r\n");
  #endif
  W25Q128_WriteEnable();
  W25Q128_CS_Set(0);
  W25Q128_SPI(0xC7);
  W25Q128_CS_Set(1);
  W25Q128_WaitForWriteEnd();
  #if (W25Q128_DEBUG==1)
    printf("w25q128 EraseBlock done after %ld ms!\r\n",HAL_GetTick()-StartTime);
  #endif
  W25Q128_Delay(10);
  w25q128.Lock=0;
}

void W25Q128_EraseSector(uint32_t SectorAddr)
{
  while(w25q128.Lock==1)
    W25Q128_Delay(1);
  w25q128.Lock=1;
  #if (W25Q128_DEBUG==1)
    uint32_t	StartTime=HAL_GetTick();
    printf("w25q128 EraseSector %ld Begin...\r\n",SectorAddr);
  #endif
  W25Q128_WaitForWriteEnd();
  SectorAddr = SectorAddr * w25q128.SectorSize;
  W25Q128_WriteEnable();
  W25Q128_CS_Set(0);
  W25Q128_SPI(0x20);
  W25Q128_SPI((SectorAddr & 0xFF0000) >> 16);
  W25Q128_SPI((SectorAddr & 0xFF00) >> 8);
  W25Q128_SPI(SectorAddr & 0xFF);
	W25Q128_CS_Set(1);
  W25Q128_WaitForWriteEnd();
  #if (W25Q128_DEBUG==1)
    printf("w25q128 EraseSector done after %ld ms\r\n",HAL_GetTick()-StartTime);
  #endif
  W25Q128_Delay(1);
  w25q128.Lock=0;
}

void W25Q128_EraseBlock(uint32_t BlockAddr)
{
  while(w25q128.Lock==1)
    W25Q128_Delay(1);
  w25q128.Lock=1;
  #if (W25Q128_DEBUG==1)
    printf("w25q128 EraseBlock %ld Begin...\r\n",BlockAddr);
    W25Q128_Delay(100);
    uint32_t	StartTime=HAL_GetTick();
  #endif
  W25Q128_WaitForWriteEnd();
  BlockAddr = BlockAddr * w25q128.SectorSize*16;
  W25Q128_WriteEnable();
  W25Q128_CS_Set(0);
  W25Q128_SPI(0xD8);
  W25Q128_SPI((BlockAddr & 0xFF0000) >> 16);
  W25Q128_SPI((BlockAddr & 0xFF00) >> 8);
  W25Q128_SPI(BlockAddr & 0xFF);
	W25Q128_CS_Set(1);
  W25Q128_WaitForWriteEnd();
  #if (W25Q128_DEBUG==1)
    printf("w25q128 EraseBlock done after %ld ms\r\n",HAL_GetTick()-StartTime);
    W25Q128_Delay(100);
  #endif
  W25Q128_Delay(1);
  w25q128.Lock=0;
}

uint32_t W25Q128_PageToSector(uint32_t	PageAddress)
{
  return ((PageAddress*w25q128.PageSize)/w25q128.SectorSize);
}

uint32_t W25Q128_PageToBlock(uint32_t	PageAddress)
{
  return ((PageAddress*w25q128.PageSize)/w25q128.BlockSize);
}

uint32_t W25Q128_SectorToBlock(uint32_t	SectorAddress)
{
  return ((SectorAddress*w25q128.SectorSize)/w25q128.BlockSize);
}

uint32_t W25Q128_SectorToPage(uint32_t	SectorAddress)
{
  return (SectorAddress*w25q128.SectorSize)/w25q128.PageSize;
}

uint32_t W25Q128_BlockToPage(uint32_t	BlockAddress)
{
  return (BlockAddress*w25q128.BlockSize)/w25q128.PageSize;
}

uint32_t W25Q128_IsEmptyPage(uint32_t Page_Address,uint32_t OffsetInByte,uint32_t NumByteToCheck_up_to_PageSize)
{
  while(w25q128.Lock==1)
  W25Q128_Delay(1);
  w25q128.Lock=1;
  if(((NumByteToCheck_up_to_PageSize+OffsetInByte)>w25q128.PageSize)||(NumByteToCheck_up_to_PageSize==0))
    NumByteToCheck_up_to_PageSize=w25q128.PageSize-OffsetInByte;
  #if (W25Q128_DEBUG==1)
    printf("w25q128 CheckPage:%ld, Offset:%ld, Bytes:%ld begin...\r\n",Page_Address,OffsetInByte,NumByteToCheck_up_to_PageSize);
    W25Q128_Delay(100);
    uint32_t	StartTime=HAL_GetTick();
  #endif

  uint8_t	pBuffer[32];
  uint32_t	WorkAddress;
  uint32_t	i;

  for(i=OffsetInByte; i<w25q128.PageSize; i+=sizeof(pBuffer))
  {
	W25Q128_CS_Set(0);
	WorkAddress=(i+Page_Address*w25q128.PageSize);
	W25Q128_SPI(0x0B);
	W25Q128_SPI((WorkAddress & 0xFF0000) >> 16);
	W25Q128_SPI((WorkAddress & 0xFF00) >> 8);
	W25Q128_SPI(WorkAddress & 0xFF);
	W25Q128_SPI(0);
	HAL_SPI_Receive(&Hard_SPI,pBuffer,sizeof(pBuffer),100);
	W25Q128_CS_Set(1);
	for(uint8_t x=0;x<sizeof(pBuffer);x++)
	{
	  if(pBuffer[x]!=0xFF)
	    goto NOT_EMPTY;
	}
  }
  if((w25q128.PageSize+OffsetInByte)%sizeof(pBuffer)!=0)
  {
	i-=sizeof(pBuffer);
	for( ; i<w25q128.PageSize; i++)
	{
	  W25Q128_CS_Set(0);
	  WorkAddress=(i+Page_Address*w25q128.PageSize);
	  W25Q128_SPI(0x0B);
	  W25Q128_SPI((WorkAddress & 0xFF0000) >> 16);
	  W25Q128_SPI((WorkAddress & 0xFF00) >> 8);
	  W25Q128_SPI(WorkAddress & 0xFF);
	  W25Q128_SPI(0);
	  HAL_SPI_Receive(&Hard_SPI,pBuffer,1,100);
	  W25Q128_CS_Set(1);
	  if(pBuffer[0]!=0xFF)
		  goto NOT_EMPTY;
	}
  }
  #if (W25Q128_DEBUG==1)
    printf("w25q128 CheckPage is Empty in %ld ms\r\n",HAL_GetTick()-StartTime);
    W25Q128_Delay(100);
  #endif
  w25q128.Lock=0;
  return 1;
  NOT_EMPTY:
  #if (W25Q128_DEBUG==1)
    printf("w25q128 CheckPage is Not Empty in %ld ms\r\n",HAL_GetTick()-StartTime);
    W25Q128_Delay(100);
  #endif
  w25q128.Lock=0;
  return 0;
}

uint32_t W25Q128_IsEmptySector(uint32_t Sector_Address,uint32_t OffsetInByte,uint32_t NumByteToCheck_up_to_SectorSize)
{
  while(w25q128.Lock==1)
  W25Q128_Delay(1);
  w25q128.Lock=1;
  if((NumByteToCheck_up_to_SectorSize>w25q128.SectorSize)||(NumByteToCheck_up_to_SectorSize==0))
    NumByteToCheck_up_to_SectorSize=w25q128.SectorSize;
  #if (W25Q128_DEBUG==1)
    printf("w25q128 CheckSector:%ld, Offset:%ld, Bytes:%ld begin...\r\n",Sector_Address,OffsetInByte,NumByteToCheck_up_to_SectorSize);
    W25Q128_Delay(100);
    uint32_t	StartTime=HAL_GetTick();
  #endif
	
  uint8_t	pBuffer[32];
  uint32_t	WorkAddress;
  uint32_t	i;

  for(i=OffsetInByte; i<w25q128.SectorSize; i+=sizeof(pBuffer))
  {
	W25Q128_CS_Set(0);
	WorkAddress=(i+Sector_Address*w25q128.SectorSize);
	W25Q128_SPI(0x0B);
	W25Q128_SPI((WorkAddress & 0xFF0000) >> 16);
	W25Q128_SPI((WorkAddress & 0xFF00) >> 8);
	W25Q128_SPI(WorkAddress & 0xFF);
	W25Q128_SPI(0);
	HAL_SPI_Receive(&Hard_SPI,pBuffer,sizeof(pBuffer),100);
	W25Q128_CS_Set(1);
	for(uint8_t x=0;x<sizeof(pBuffer);x++)
	{
	  if(pBuffer[x]!=0xFF)
		goto NOT_EMPTY;
	}
  }
  if((w25q128.SectorSize+OffsetInByte)%sizeof(pBuffer)!=0)
  {
	i-=sizeof(pBuffer);
	for( ; i<w25q128.SectorSize; i++)
	{
	  W25Q128_CS_Set(0);
	  WorkAddress=(i+Sector_Address*w25q128.SectorSize);
	  W25Q128_SPI(0x0B);
	  W25Q128_SPI((WorkAddress & 0xFF0000) >> 16);
	  W25Q128_SPI((WorkAddress & 0xFF00) >> 8);
	  W25Q128_SPI(WorkAddress & 0xFF);
	  W25Q128_SPI(0);
	  HAL_SPI_Receive(&Hard_SPI,pBuffer,1,100);
	  W25Q128_CS_Set(1);
	  if(pBuffer[0]!=0xFF)
		goto NOT_EMPTY;
	}
  }
  #if (W25Q128_DEBUG==1)
    printf("w25q128 CheckSector is Empty in %ld ms\r\n",HAL_GetTick()-StartTime);
    W25Q128_Delay(100);
  #endif
  w25q128.Lock=0;
  return 1;
  NOT_EMPTY:
  #if (W25Q128_DEBUG==1)
    printf("w25q128 CheckSector is Not Empty in %ld ms\r\n",HAL_GetTick()-StartTime);
    W25Q128_Delay(100);
  #endif
  w25q128.Lock=0;
  return 0;
}

uint32_t W25Q128_IsEmptyBlock(uint32_t Block_Address,uint32_t OffsetInByte,uint32_t NumByteToCheck_up_to_BlockSize)
{
  while(w25q128.Lock==1)
  W25Q128_Delay(1);
  w25q128.Lock=1;
  if((NumByteToCheck_up_to_BlockSize>w25q128.BlockSize)||(NumByteToCheck_up_to_BlockSize==0))
	NumByteToCheck_up_to_BlockSize=w25q128.BlockSize;
  #if (W25Q128_DEBUG==1)
    printf("w25q128 CheckBlock:%ld, Offset:%ld, Bytes:%ld begin...\r\n",Block_Address,OffsetInByte,NumByteToCheck_up_to_BlockSize);
    W25Q128_Delay(100);
    uint32_t	StartTime=HAL_GetTick();
  #endif

  uint8_t	pBuffer[32];
  uint32_t	WorkAddress;
  uint32_t	i;

  for(i=OffsetInByte; i<w25q128.BlockSize; i+=sizeof(pBuffer))
  {
	W25Q128_CS_Set(0);
	WorkAddress=(i+Block_Address*w25q128.BlockSize);
	W25Q128_SPI(0x0B);
	W25Q128_SPI((WorkAddress & 0xFF0000) >> 16);
	W25Q128_SPI((WorkAddress & 0xFF00) >> 8);
	W25Q128_SPI(WorkAddress & 0xFF);
	W25Q128_SPI(0);
	HAL_SPI_Receive(&Hard_SPI,pBuffer,sizeof(pBuffer),100);
	W25Q128_CS_Set(1);
	for(uint8_t x=0;x<sizeof(pBuffer);x++)
	{
	  if(pBuffer[x]!=0xFF)
		goto NOT_EMPTY;
	}
  }
  if((w25q128.BlockSize+OffsetInByte)%sizeof(pBuffer)!=0)
  {
	i-=sizeof(pBuffer);
	for( ; i<w25q128.BlockSize; i++)
	{
	  W25Q128_CS_Set(0);
	  WorkAddress=(i+Block_Address*w25q128.BlockSize);
	  W25Q128_SPI(0x0B);
	  W25Q128_SPI((WorkAddress & 0xFF0000) >> 16);
	  W25Q128_SPI((WorkAddress & 0xFF00) >> 8);
	  W25Q128_SPI(WorkAddress & 0xFF);
	  W25Q128_SPI(0);
	  HAL_SPI_Receive(&Hard_SPI,pBuffer,1,100);
	  W25Q128_CS_Set(1);
	  if(pBuffer[0]!=0xFF)
		goto NOT_EMPTY;
	}
  }
  #if (W25Q128_DEBUG==1)
    printf("w25q128 CheckBlock is Empty in %ld ms\r\n",HAL_GetTick()-StartTime);
    W25Q128_Delay(100);
  #endif
  w25q128.Lock=0;
  return 1;
  NOT_EMPTY:
  #if (W25Q128_DEBUG==1)
    printf("w25q128 CheckBlock is Not Empty in %ld ms\r\n",HAL_GetTick()-StartTime);
    W25Q128_Delay(100);
  #endif
  w25q128.Lock=0;
  return 0;
}

void W25Q128_WriteByte(uint8_t pBuffer, uint32_t WriteAddr_inBytes)
{
  while(w25q128.Lock==1)
	W25Q128_Delay(1);
  w25q128.Lock=1;
  #if (W25Q128_DEBUG==1)
    uint32_t	StartTime=HAL_GetTick();
    printf("w25q128 WriteByte 0x%02X at address %ld begin...",pBuffer,WriteAddr_inBytes);
  #endif
  W25Q128_WaitForWriteEnd();
  W25Q128_WriteEnable();
  W25Q128_CS_Set(0);
  W25Q128_SPI(0x02);
  W25Q128_SPI((WriteAddr_inBytes & 0xFF0000) >> 16);
  W25Q128_SPI((WriteAddr_inBytes & 0xFF00) >> 8);
  W25Q128_SPI(WriteAddr_inBytes & 0xFF);
  W25Q128_SPI(pBuffer);
  W25Q128_CS_Set(1);
  W25Q128_WaitForWriteEnd();
  #if (W25Q128_DEBUG==1)
    printf("w25q128 WriteByte done after %ld ms\r\n",HAL_GetTick()-StartTime);
  #endif
  w25q128.Lock=0;
}

void W25Q128_WritePage(uint8_t *pBuffer	,uint32_t Page_Address,uint32_t OffsetInByte,uint32_t NumByteToWrite_up_to_PageSize)
{
  while(w25q128.Lock==1)
	W25Q128_Delay(1);
  w25q128.Lock=1;
  if(((NumByteToWrite_up_to_PageSize+OffsetInByte)>w25q128.PageSize)||(NumByteToWrite_up_to_PageSize==0))
	NumByteToWrite_up_to_PageSize=w25q128.PageSize-OffsetInByte;
  if((OffsetInByte+NumByteToWrite_up_to_PageSize) > w25q128.PageSize)
	NumByteToWrite_up_to_PageSize = w25q128.PageSize-OffsetInByte;
  #if (W25Q128_DEBUG==1)
    printf("w25q128 WritePage:%ld, Offset:%ld ,Writes %ld Bytes, begin...\r\n",Page_Address,OffsetInByte,NumByteToWrite_up_to_PageSize);
    W25Q128_Delay(100);
    uint32_t	StartTime=HAL_GetTick();
  #endif
  W25Q128_WaitForWriteEnd();
  W25Q128_WriteEnable();
  W25Q128_CS_Set(0);
  W25Q128_SPI(0x02);
  Page_Address = (Page_Address*w25q128.PageSize)+OffsetInByte;
  W25Q128_SPI((Page_Address & 0xFF0000) >> 16);
  W25Q128_SPI((Page_Address & 0xFF00) >> 8);
  W25Q128_SPI(Page_Address&0xFF);
  HAL_SPI_Transmit(&Hard_SPI,pBuffer,NumByteToWrite_up_to_PageSize,100);
  W25Q128_CS_Set(1);
  W25Q128_WaitForWriteEnd();
  #if (W25Q128_DEBUG==1)
    StartTime = HAL_GetTick()-StartTime;
    for(uint32_t i=0;i<NumByteToWrite_up_to_PageSize ; i++)
    {
	  if((i%8==0)&&(i>2))
	  {
		printf("\r\n");
		W25Q128_Delay(10);
	  }
	  printf("0x%02X,",pBuffer[i]);
    }
    printf("\r\n");
    printf("w25q128 WritePage done after %ld ms\r\n",StartTime);
    W25Q128_Delay(100);
  #endif
  W25Q128_Delay(1);
  w25q128.Lock=0;
}

void W25Q128_WriteSector(uint8_t *pBuffer	,uint32_t Sector_Address,uint32_t OffsetInByte	,uint32_t NumByteToWrite_up_to_SectorSize)
{
  if((NumByteToWrite_up_to_SectorSize>w25q128.SectorSize)||(NumByteToWrite_up_to_SectorSize==0))
	NumByteToWrite_up_to_SectorSize=w25q128.SectorSize;
  #if (W25Q128_DEBUG==1)
    printf("+++w25q128 WriteSector:%ld, Offset:%ld ,Write %ld Bytes, begin...\r\n",Sector_Address,OffsetInByte,NumByteToWrite_up_to_SectorSize);
    W25Q128_Delay(100);
  #endif
  if(OffsetInByte>=w25q128.SectorSize)
  {
	#if (W25Q128_DEBUG==1)
	  printf("---w25q128 WriteSector Faild!\r\n");
	  W25Q128_Delay(100);
	#endif
	return;
  }

  uint32_t	StartPage;
  int32_t		BytesToWrite;
  uint32_t	LocalOffset;

  if((OffsetInByte+NumByteToWrite_up_to_SectorSize) > w25q128.SectorSize)
	BytesToWrite = w25q128.SectorSize-OffsetInByte;
  else
	BytesToWrite = NumByteToWrite_up_to_SectorSize;
  StartPage = W25Q128_SectorToPage(Sector_Address)+(OffsetInByte/w25q128.PageSize);
  LocalOffset = OffsetInByte%w25q128.PageSize;
  do
  {
	W25Q128_WritePage(pBuffer,StartPage,LocalOffset,BytesToWrite);
	StartPage++;
	BytesToWrite-=w25q128.PageSize-LocalOffset;
	pBuffer += w25q128.PageSize - LocalOffset;
	LocalOffset=0;
  }while(BytesToWrite>0);
  #if (W25Q128_DEBUG==1)
    printf("---w25q128 WriteSector Done\r\n");
    W25Q128_Delay(100);
  #endif
}

void W25Q128_WriteBlock	(uint8_t* pBuffer ,uint32_t Block_Address	,uint32_t OffsetInByte	,uint32_t	NumByteToWrite_up_to_BlockSize)
{
  if((NumByteToWrite_up_to_BlockSize>w25q128.BlockSize)||(NumByteToWrite_up_to_BlockSize==0))
	NumByteToWrite_up_to_BlockSize=w25q128.BlockSize;
  #if (W25Q128_DEBUG==1)
    printf("+++w25q128 WriteBlock:%ld, Offset:%ld ,Write %ld Bytes, begin...\r\n",Block_Address,OffsetInByte,NumByteToWrite_up_to_BlockSize);
    W25Q128_Delay(100);
  #endif
  if(OffsetInByte>=w25q128.BlockSize)
  {
	#if (W25Q128_DEBUG==1)
      printf("---w25q128 WriteBlock Faild!\r\n");
      W25Q128_Delay(100);
	#endif
	return;
  }

  uint32_t	StartPage;
  int32_t		BytesToWrite;
  uint32_t	LocalOffset;

  if((OffsetInByte+NumByteToWrite_up_to_BlockSize) > w25q128.BlockSize)
	BytesToWrite = w25q128.BlockSize-OffsetInByte;
  else
	BytesToWrite = NumByteToWrite_up_to_BlockSize;
  StartPage = W25Q128_BlockToPage(Block_Address)+(OffsetInByte/w25q128.PageSize);
  LocalOffset = OffsetInByte%w25q128.PageSize;
  do
  {
    W25Q128_WritePage(pBuffer,StartPage,LocalOffset,BytesToWrite);
    StartPage++;
    BytesToWrite-=w25q128.PageSize-LocalOffset;
    pBuffer += w25q128.PageSize - LocalOffset;
    LocalOffset=0;
  }while(BytesToWrite>0);
  #if (W25Q128_DEBUG==1)
    printf("---w25q128 WriteBlock Done\r\n");
    W25Q128_Delay(100);
  #endif
}

void W25Q128_ReadByte(uint8_t *pBuffer,uint32_t Bytes_Address)
{
  while(w25q128.Lock==1)
	W25Q128_Delay(1);
  w25q128.Lock=1;
  #if (W25Q128_DEBUG==1)
    uint32_t	StartTime=HAL_GetTick();
    printf("w25q128 ReadByte at address %ld begin...\r\n",Bytes_Address);
  #endif
  W25Q128_CS_Set(0);
  W25Q128_SPI(0x0B);
  W25Q128_SPI((Bytes_Address & 0xFF0000) >> 16);
  W25Q128_SPI((Bytes_Address& 0xFF00) >> 8);
  W25Q128_SPI(Bytes_Address & 0xFF);
  W25Q128_SPI(0);
  *pBuffer = W25Q128_SPI(W25Q128_DUMMY_BYTE);
  W25Q128_CS_Set(1);
  #if (W25Q128_DEBUG==1)
    printf("w25q128 ReadByte 0x%02X done after %ld ms\r\n",*pBuffer,HAL_GetTick()-StartTime);
  #endif
  w25q128.Lock=0;
}

void W25Q128_ReadBytes(uint8_t* pBuffer, uint32_t ReadAddr, uint32_t NumByteToRead)
{
  while(w25q128.Lock==1)
	W25Q128_Delay(1);
  w25q128.Lock=1;
  #if (W25Q128_DEBUG==1)
    uint32_t	StartTime=HAL_GetTick();
    printf("w25q128 ReadBytes at Address:%ld, %ld Bytes  begin...\r\n",ReadAddr,NumByteToRead);
  #endif
  W25Q128_CS_Set(0);
  W25Q128_SPI(0x0B);
  W25Q128_SPI((ReadAddr & 0xFF0000) >> 16);
  W25Q128_SPI((ReadAddr& 0xFF00) >> 8);
  W25Q128_SPI(ReadAddr & 0xFF);
  W25Q128_SPI(0);
  HAL_SPI_Receive(&Hard_SPI,pBuffer,NumByteToRead,2000);
  W25Q128_CS_Set(1);
  #if (W25Q128_DEBUG==1)
    StartTime = HAL_GetTick()-StartTime;
    for(uint32_t i=0;i<NumByteToRead;i++)
    {
	  if((i%8==0)&&(i>2))
	  {
	    printf("\r\n");
	    W25Q128_Delay(10);
	  }
	  printf("0x%02X,",pBuffer[i]);
    }
    printf("\r\n");
    printf("w25q128 ReadBytes done after %ld ms\r\n",StartTime);
    W25Q128_Delay(100);
  #endif
  W25Q128_Delay(1);
  w25q128.Lock=0;
}

void W25Q128_ReadPage(uint8_t *pBuffer,uint32_t Page_Address,uint32_t OffsetInByte,uint32_t NumByteToRead_up_to_PageSize)
{
  while(w25q128.Lock==1)
	W25Q128_Delay(1);
  w25q128.Lock=1;
  if((NumByteToRead_up_to_PageSize>w25q128.PageSize)||(NumByteToRead_up_to_PageSize==0))
	NumByteToRead_up_to_PageSize=w25q128.PageSize;
  if((OffsetInByte+NumByteToRead_up_to_PageSize) > w25q128.PageSize)
	NumByteToRead_up_to_PageSize = w25q128.PageSize-OffsetInByte;
  #if (W25Q128_DEBUG==1)
    printf("w25q128 ReadPage:%ld, Offset:%ld ,Read %ld Bytes, begin...\r\n",Page_Address,OffsetInByte,NumByteToRead_up_to_PageSize);
    W25Q128_Delay(100);
    uint32_t	StartTime=HAL_GetTick();
  #endif
  Page_Address = Page_Address*w25q128.PageSize+OffsetInByte;
  W25Q128_CS_Set(0);
  W25Q128_SPI(0x0B);
  W25Q128_SPI((Page_Address & 0xFF0000) >> 16);
  W25Q128_SPI((Page_Address& 0xFF00) >> 8);
  W25Q128_SPI(Page_Address & 0xFF);
  W25Q128_SPI(0);
  HAL_SPI_Receive(&Hard_SPI,pBuffer,NumByteToRead_up_to_PageSize,100);
  W25Q128_CS_Set(1);
  #if (W25Q128_DEBUG==1)
    StartTime = HAL_GetTick()-StartTime;
    for(uint32_t i=0;i<NumByteToRead_up_to_PageSize ; i++)
    {
	  if((i%8==0)&&(i>2))
	  {
	    printf("\r\n");
	    W25Q128_Delay(10);
	  }
	  printf("0x%02X,",pBuffer[i]);
    }
    printf("\r\n");
    printf("w25q128 ReadPage done after %ld ms\r\n",StartTime);
    W25Q128_Delay(100);
  #endif
  W25Q128_Delay(1);
  w25q128.Lock=0;
}

void W25Q128_ReadSector(uint8_t *pBuffer,uint32_t Sector_Address,uint32_t OffsetInByte,uint32_t NumByteToRead_up_to_SectorSize)
{
  if((NumByteToRead_up_to_SectorSize>w25q128.SectorSize)||(NumByteToRead_up_to_SectorSize==0))
	NumByteToRead_up_to_SectorSize=w25q128.SectorSize;
  #if (W25Q128_DEBUG==1)
    printf("+++w25q128 ReadSector:%ld, Offset:%ld ,Read %ld Bytes, begin...\r\n",Sector_Address,OffsetInByte,NumByteToRead_up_to_SectorSize);
    W25Q128_Delay(100);
  #endif
  if(OffsetInByte>=w25q128.SectorSize)
  {
	#if (W25Q128_DEBUG==1)
      printf("---w25q128 ReadSector Faild!\r\n");
      W25Q128_Delay(100);
	#endif
	return;
  }

  uint32_t	StartPage;
  int32_t		BytesToRead;
  uint32_t	LocalOffset;

  if((OffsetInByte+NumByteToRead_up_to_SectorSize) > w25q128.SectorSize)
	BytesToRead = w25q128.SectorSize-OffsetInByte;
  else
	BytesToRead = NumByteToRead_up_to_SectorSize;
  StartPage = W25Q128_SectorToPage(Sector_Address)+(OffsetInByte/w25q128.PageSize);
  LocalOffset = OffsetInByte%w25q128.PageSize;
  do
  {
    W25Q128_ReadPage(pBuffer,StartPage,LocalOffset,BytesToRead);
    StartPage++;
    BytesToRead-=w25q128.PageSize-LocalOffset;
    pBuffer += w25q128.PageSize - LocalOffset;
    LocalOffset=0;
  }while(BytesToRead>0);
  #if (W25Q128_DEBUG==1)
    printf("---w25q128 ReadSector Done\r\n");
    W25Q128_Delay(100);
  #endif
}

void W25Q128_ReadBlock(uint8_t* pBuffer,uint32_t Block_Address,uint32_t OffsetInByte,uint32_t	NumByteToRead_up_to_BlockSize)
{
  if((NumByteToRead_up_to_BlockSize>w25q128.BlockSize)||(NumByteToRead_up_to_BlockSize==0))
	NumByteToRead_up_to_BlockSize=w25q128.BlockSize;
  #if (W25Q128_DEBUG==1)
    printf("+++w25q128 ReadBlock:%ld, Offset:%ld ,Read %ld Bytes, begin...\r\n",Block_Address,OffsetInByte,NumByteToRead_up_to_BlockSize);
    W25Q128_Delay(100);
  #endif
  if(OffsetInByte>=w25q128.BlockSize)
  {
	#if (W25Q128_DEBUG==1)
	  printf("w25q128 ReadBlock Faild!\r\n");
	  W25Q128_Delay(100);
	#endif
	return;
  }

  uint32_t	StartPage;
  int32_t		BytesToRead;
  uint32_t	LocalOffset;

  if((OffsetInByte+NumByteToRead_up_to_BlockSize) > w25q128.BlockSize)
    BytesToRead = w25q128.BlockSize-OffsetInByte;
  else
	BytesToRead = NumByteToRead_up_to_BlockSize;
  StartPage = W25Q128_BlockToPage(Block_Address)+(OffsetInByte/w25q128.PageSize);
  LocalOffset = OffsetInByte%w25q128.PageSize;
  do
  {
    W25Q128_ReadPage(pBuffer,StartPage,LocalOffset,BytesToRead);
    StartPage++;
    BytesToRead-=w25q128.PageSize-LocalOffset;
    pBuffer += w25q128.PageSize - LocalOffset;
    LocalOffset=0;
  }while(BytesToRead>0);
  #if (W25Q128_DEBUG==1)
    printf("---w25q128 ReadBlock Done\r\n");
    W25Q128_Delay(100);
  #endif
}
